package filter

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"gitee.com/kobeyyf/apibox/handler"
)

type filterFunc func(c *handler.Context, param string) *handler.Response

type Filter interface {
	Handler(c *handler.Context, param string) *handler.Response
}

type BaseFilter struct {
	handlers []filterFunc
}

func (baseFilter *BaseFilter) Handler(c *handler.Context, param string) *handler.Response {
	for _, handlerFunc := range baseFilter.handlers {
		resp := handlerFunc(c, param)
		if resp != nil {
			return resp
		}
	}
	return nil
}

type FilterDefault struct {
	value interface{}
}

func (filterDefault *FilterDefault) Handler(c *handler.Context, param string) *handler.Response {
	_, has := c.Request.Form[param]
	if !has {
		c.Request.Form.Set(param, fmt.Sprint(filterDefault.value))
	}
	return nil
}

func Default(v interface{}) *FilterDefault {
	return &FilterDefault{value: v}
}

type FilterEmptyToNil struct{}

func (emptyToNil *FilterEmptyToNil) Handler(c *handler.Context, param string) *handler.Response {
	value := c.Request.Form.Get(param)
	if value == "" {
		c.Request.Form.Del(param)
	}
	return nil
}

func EmptyToNil() *FilterEmptyToNil {
	return &FilterEmptyToNil{}
}

type FilterRequired struct {
}

func (required *FilterRequired) Handler(c *handler.Context, param string) *handler.Response {
	_, has := c.Request.Form[param]
	if !has {
		return handler.NewErrorResponseWith400(handler.ErrorCode_MissingParameter, fmt.Sprintf("miss request param : %s", param))
	}
	return nil
}

func Required() Filter {
	return &FilterRequired{}
}

type FilterString struct {
	*BaseFilter
}

func (filterString *FilterString) Handler(c *handler.Context, param string) *handler.Response {
	for _, handleFunc := range filterString.handlers {
		resp := handleFunc(c, param)
		if resp != nil {
			return resp
		}
	}
	return nil
}

func (filterString *FilterString) In(in []string) *FilterString {
	f := func(c *handler.Context, param string) *handler.Response {

		_, has := c.Request.Form[param]
		if has {
			value := c.Request.Form.Get(param)
			for _, need := range in {
				if value == need {
					return nil
				}
			}
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s need in %s", param, strings.Join(in, "/")))
		}
		return nil
	}
	filterString.handlers = append(filterString.handlers, f)
	return filterString
}

func String() *FilterString {
	return &FilterString{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 0, 1),
		},
	}
}

type FilterStringSet struct {
	*BaseFilter
}

func (filterString *FilterStringSet) Handler(c *handler.Context, param string) *handler.Response {
	for _, handleFunc := range filterString.handlers {
		resp := handleFunc(c, param)
		if resp != nil {
			return resp
		}
	}
	return nil
}

func StringSet() *FilterStringSet {
	return &FilterStringSet{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 0, 1),
		},
	}
}

type FilterInt struct {
	*BaseFilter
}

func (filterInt *FilterInt) In(start, end int) *FilterInt {
	f := func(c *handler.Context, param string) *handler.Response {
		reqParamInt, _ := strconv.Atoi(c.Request.Form.Get(param))
		if reqParamInt < start {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too small", param))
		}
		if reqParamInt > end {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too big", param))
		}
		return nil
	}
	filterInt.handlers = append(filterInt.handlers, f)
	return filterInt
}

func Int() *FilterInt {
	f := &FilterInt{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		value, has := c.Request.Form[param]
		if has {
			// if len(value) != 1 {
			// 	return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type int", param))
			// }
			_, err := strconv.Atoi(value[0])
			if err != nil {
				return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type int", param))
			}
		}
		return nil
	}
	return f
}

type FilterUint64 struct {
	*BaseFilter
}

func (filterUint64 *FilterUint64) In(start, end uint64) *FilterUint64 {
	f := func(c *handler.Context, param string) *handler.Response {
		reqParamUint64, _ := strconv.ParseUint(c.Request.Form.Get(param), 10, 64)
		if reqParamUint64 < start {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too small", param))
		}
		if reqParamUint64 > end {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too big", param))
		}
		return nil
	}
	filterUint64.handlers = append(filterUint64.handlers, f)
	return filterUint64

}

func Uint64() *FilterUint64 {
	f := &FilterUint64{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		value, has := c.Request.Form[param]
		if has {
			// if len(value) != 1 {
			// 	return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64", param))
			// }
			_, err := strconv.ParseUint(value[0], 10, 64)
			if err != nil {
				return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64", param))
			}
		}
		return nil
	}
	return f
}

type FilterUint32 struct {
	*BaseFilter
}

func (filterUint32 *FilterUint32) In(start, end uint32) *FilterUint32 {
	f := func(c *handler.Context, param string) *handler.Response {
		reqParamUint64, _ := strconv.ParseUint(c.Request.Form.Get(param), 10, 32)
		reqParamUint32 := uint32(reqParamUint64)
		if reqParamUint32 < start {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too small", param))
		}
		if reqParamUint32 > end {
			return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("%s is too big", param))
		}
		return nil
	}
	filterUint32.handlers = append(filterUint32.handlers, f)
	return filterUint32

}

func Uint32() *FilterUint32 {
	f := &FilterUint32{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		value, has := c.Request.Form[param]
		if has {
			// if len(value) != 1 {
			// 	return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64", param))
			// }
			_, err := strconv.ParseUint(value[0], 10, 32)
			if err != nil {
				return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64", param))
			}
		}
		return nil
	}
	return f
}

type FilterUint64Set struct {
	*BaseFilter
}

func Uint64Set() *FilterUint64Set {
	f := &FilterUint64Set{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		values, has := c.Request.Form[param]
		if has {
			for _, value := range values {
				_, err := strconv.ParseUint(value, 10, 64)
				if err != nil {
					return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64:%s", param, value))
				}
			}
		}
		return nil
	}
	return f
}

type FilterUint32Set struct {
	*BaseFilter
}

func Uint32Set() *FilterUint32Set {
	f := &FilterUint32Set{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		values, has := c.Request.Form[param]
		if has {
			for _, value := range values {
				_, err := strconv.ParseUint(value, 10, 32)
				if err != nil {
					return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64:%s", param, value))
				}
			}
		}
		return nil
	}
	return f
}

type FilterInt32Set struct {
	*BaseFilter
}

func Int32Set() *FilterInt32Set {
	f := &FilterInt32Set{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		values, has := c.Request.Form[param]
		if has {
			for _, value := range values {
				_, err := strconv.ParseInt(value, 10, 32)
				if err != nil {
					return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, fmt.Sprintf("params %s not type uint64:%s", param, value))
				}
			}
		}
		return nil
	}
	return f
}

type FilterPhoneNumer struct {
	// reg := `^1([38][0-9]|14[57]|5[^4])\d{8}$`
	// rgx := regexp.MustCompile(reg)
	rgx *regexp.Regexp
	*BaseFilter
}

func PhoneNumer() *FilterPhoneNumer {
	f := &FilterPhoneNumer{
		BaseFilter: &BaseFilter{
			handlers: make([]filterFunc, 1, 2),
		},
		rgx: regexp.MustCompile(`^(1[3|4|5|6|7|8|9][0-9]\d{4,8})$`),
	}
	f.handlers[0] = func(c *handler.Context, param string) *handler.Response {
		values, has := c.Request.Form[param]
		if has {
			ok := f.rgx.MatchString(values[0])
			if !ok {
				return handler.NewErrorResponseWith400(handler.ErrorCode_InvalidParamater, "请输入有效的手机号")
			}
		}
		return nil
	}
	return f
}
